﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Research.Kinect.Nui;
using System.Runtime.InteropServices;
using System.Collections;

namespace KinectAssistant
{
    class PPTMotionDetector : MotionDetector
    {
        private Runtime kinectNui;

        private ArrayList lhandtrack = new ArrayList();

        private ArrayList rhandtrack = new ArrayList();

        public string slideName;

        private int frameCount = 0;
        // Get a handle to an application window.
        [DllImport("USER32.DLL")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        // Activate an application window.
        [DllImport("USER32.DLL")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        // Constructor
        public PPTMotionDetector(string slide)
        {
            this.slideName = slide;
        }

        private void InitializeNui()
        {
            try
            {
                kinectNui = new Runtime();

                //kinectNui.Initialize(RuntimeOptions.UseColor | RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseColor);
                kinectNui.Initialize(RuntimeOptions.UseSkeletalTracking);

                //kinectNui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.ColorYuv);

                kinectNui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(SkeletonFrameReady);
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void Process()
        {
            InitializeNui();
        }

        void SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            foreach (SkeletonData data in e.SkeletonFrame.Skeletons)
            {
                if (SkeletonTrackingState.Tracked != data.TrackingState) continue;

                foreach (Joint joint in data.Joints)
                {
                    if (joint.Position.W < 0.6f) return;

                    frameCount++;

                    switch (joint.ID)
                    {

                        case JointID.HandRight:
                            rhandtrack.Add(joint);
                            break;
                        case JointID.HandLeft:
                            lhandtrack.Add(joint);
                            break;
                    }
                }
            }

            if (frameCount > 5)
            {
                Joint[] rhand = (Joint[])rhandtrack.ToArray(typeof(Joint));
                Joint[] lhand = (Joint[])lhandtrack.ToArray(typeof(Joint));

                string gesture = RecognizeMovement(lhand, rhand);

                if (gesture != "?")
                    ControlPowerPoint(gesture);

                rhandtrack.Clear();
                lhandtrack.Clear();

                frameCount = 0;
            }
        }

        // Controlling PowerPoint SlideShow
        private void ControlPowerPoint(string gesture)
        {
            IntPtr powerPointHandle = FindWindow(null, "PowerPoint Slide Show - [" + slideName + "]");

            // Verify that PPS is a running process.
            if (powerPointHandle == IntPtr.Zero)
            {
                MessageBox.Show("Slide Show not running");
                return;
            }

            switch (gesture)
            {
                case "LEFT":
                    SetForegroundWindow(powerPointHandle);
                    SendKeys.SendWait("p");
                    break;

                case "RIGHT":
                    SetForegroundWindow(powerPointHandle);
                    SendKeys.SendWait("n");
                    break;

                case "UP":
                    SetForegroundWindow(powerPointHandle);
                    SendKeys.SendWait("n");
                    break;

                case "DOWN":
                    SetForegroundWindow(powerPointHandle);
                    SendKeys.SendWait("p");
                    break;
            }
        }

        private string RecognizeMovement(Joint[] lhand, Joint[] rhand)
        {
            //int l1x, l1y, l2x, l2y;
            //int llength = lhand.Length;
            //l1x = lhand[0].Position.X;
            //l1y = lhand[0].Position.Y;
            //l2x = lhand[llength-1].Position.X;
            //l2y = lhand[llength - 1].Position.Y;

            float r1x, r1y, r2x, r2y;
            int rlength = rhand.Length;
            r1x = rhand[0].Position.X;
            r1y = rhand[0].Position.Y;
            r2x = rhand[rlength - 1].Position.X;
            r2y = rhand[rlength - 1].Position.Y;


            float rdx = Math.Abs(r2x - r1x);
            float rdy = Math.Abs(r2y - r1y);

            if (rdx > rdy)
            {
                if ((rdy == 0) || ((rdx / rdy) >= 3))
                {
                    if ((r2x - r1x) > 0)
                        return "RIGHT";
                    else
                        return "LEFT";
                }
                else return "?";
            }
            else if (rdy > rdx)
            {
                if ((rdx == 0) || ((rdy / rdx) >= 3))
                {
                    if ((r2y - r1y) > 0)
                        return "DOWN";
                    else
                        return "UP";
                }
                else
                    return "?";
            }
            else
                return "?";
        }
    }
}
